package com.mo.star.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mo.star.common.BaseResponse;
import com.mo.star.common.ErrorCode;
import com.mo.star.common.ResultUtils;
import com.mo.star.contant.UserConstant;
import com.mo.star.exception.BusinessException;
import com.mo.star.mapper.UsertableMapper;
import com.mo.star.pojo.User;
import com.mo.star.service.UsertableService;
import com.mo.star.util.MD5Util;
import com.mo.star.util.MatchUtil;
import com.mo.star.util.TagsToList;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.log4j.Log4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.util.Pair;
import org.springframework.util.StopWatch;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.mo.star.contant.UserConstant.USER_LOGIN_STATE;

/**
 * @author 云赋
 * @description 针对表【usertable(数据表2)】的数据库操作Service实现
 * @createDate 2024-08-28 19:30:14
 */
@Log4j
@Service
public class UsertableServiceImpl extends ServiceImpl<UsertableMapper, User>
        implements UsertableService {
    @Resource
    UsertableMapper userMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Override
    public List<User> searchUsersByTags(List<String> tagList) {
        if (CollectionUtils.isEmpty(tagList))
            throw new BusinessException(ErrorCode.NULL_ERROR);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //拼接and查询
        for (String tags : tagList)
            queryWrapper = queryWrapper.like("tags", tags);
        List<User> userList = userMapper.selectList(queryWrapper);
        return userList.stream().map(this::getSafetyUser).collect(Collectors.toList());
    }

    public BaseResponse<Page<User>> recommendUsers() {
        return null;
    }

    @Override
    public User updateUser(User user, User userLogin) {
        log.info(user);
        log.info("已登录的用户信息" + userLogin);
        if (userLogin == null)
            throw new BusinessException(ErrorCode.NULL_ERROR);
        String userID = user.getId();
        //判断权限
        if (!userID.equals(userLogin.getId()))
            throw new BusinessException(ErrorCode.NO_AUTH);

        UpdateWrapper<User> wp = new UpdateWrapper<>();
        wp.eq("id", user.getId());
        if (user.getUsername() != null)
            wp.set("username", user.getUsername());
        if (user.getGender() != null)
            wp.set("gender", user.getGender());
        if (user.getEmail() != null)
            wp.set("email", user.getEmail());
        if (user.getPhone() != null)
            wp.set("phone", user.getPhone());

        userMapper.update(null, wp);
        User newUser = userMapper.selectById(userLogin.getId());

        return getSafetyUser(newUser);

    }

    @Override
    public User getLoginUser(HttpServletRequest request) {
        if (request == null)
            return null;
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User user = (User) userObj;
        if (userObj == null)
            throw new BusinessException(ErrorCode.NO_AUTH);
        return user;
    }

    public User userLogin(String username, String pwd, HttpServletRequest request) {
        pwd = MD5Util.getEncrypCode(pwd);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        queryWrapper.eq("pwd", pwd);
        User user = userMapper.selectOne(queryWrapper);
        // 用户不存在
        if (user == null) {
            log.info("user login failed, userAccount cannot match userPassword");
            return null;
        }
        // 3. 用户脱敏
        User safetyUser = getSafetyUser(user);
        // 4. 记录用户的登录态
        request.getSession().setAttribute(USER_LOGIN_STATE, safetyUser);

        return safetyUser;
    }

    /**
     * 用户脱敏
     */
    @Override
    public User getSafetyUser(User originUser) {
        if (originUser == null)
            return null;
        User safeUser = new User();
        safeUser.setId(originUser.getId());
        safeUser.setCreateDate(originUser.getCreateDate());
        safeUser.setUsername(originUser.getUsername());
        safeUser.setGender(originUser.getGender());
        safeUser.setEmail(originUser.getEmail());
        safeUser.setPhone(originUser.getPhone());
        safeUser.setAvatarUrl(originUser.getAvatarUrl());
        safeUser.setTags(originUser.getTags());
        safeUser.setYhsf(originUser.getYhsf());
        return safeUser;
    }

    @Override
    public User getUserById(String UserId) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",UserId);

        return userMapper.selectOne(queryWrapper);
    }

    /**
     * 是否为管理员
     *
     * @param loginUser
     * @return
     */
    @Override
    public boolean isAdmin(User loginUser) {
        return loginUser != null && loginUser.getYhsf() == UserConstant.ADMIN_ROLE;
    }

    public List<User> match(int num, User user) {
        if(user==null)
            return null;
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        List<User> userList = MatchRedis(user);
        if(userList.isEmpty())
            return null;
        stopWatch.stop();
        System.out.println("读取时间："+stopWatch.getTotalTimeMillis());
        List<String> userTags = TagsToList.tagsToList(user.getTags());
        //创建优先队列
        PriorityQueue<Pair<User,Long>> priorityQueue = new PriorityQueue<>(
                Comparator.comparing(Pair::getValue)
        );
        //用户的下标和相似度
       // List<Pair<User,Long>> list = new ArrayList<>();
        stopWatch.start();
        for (User user1 : userList) {
            String tags = user1.getTags();
            //用户的标签为String，数据库格式为[医学生, INFP],
            // 或者[\"INFP\",\"秋招\",\"黑塞\"]，如果为空，则为[],并不是null
            if (tags.equals("[]") || user.getId().equals(user1.getId())) {
                continue;
            }
            List<String> MatchUserTags = TagsToList.tagsToList(tags);
            long distance = MatchUtil.minDistance(userTags, MatchUserTags);
            //优先队列实时排序
            priorityQueue.offer(new Pair<>(user1, distance));
            // Pair<User,Long> pair =new Pair<>(user1,distance);
            //list.add(pair);
        }
        List<Pair<User,Long>> topUserPairList = new ArrayList<>();
        int count = 0;
        while (!priorityQueue.isEmpty() && count<num){
            topUserPairList.add(priorityQueue.poll());
            count++;
        }
        stopWatch.stop();
        System.out.println("匹配时间："+stopWatch.getTotalTimeMillis());
        //对相似度进行排序
        /*
        List<Pair<User,Long>> topUserPairList = list.stream()
                .sorted((a,b)->(int) (a.getValue() -b.getValue()))
                .limit(num)
                .toList();

         */
        stopWatch.start();
        List<User> finalUserList =topUserPairList.stream()
                .map(Pair::getKey).toList();
        stopWatch.stop();
        System.out.println("排序时间："+stopWatch.getTotalTimeMillis());
        if(CollectionUtils.isEmpty(finalUserList))
            log.info("无匹配用户");
        return finalUserList;
    }

    /**
     *读写redis缓存
     * @param loginUser
     * @return
     */
    public Page<User> doRedis(User loginUser){
        ValueOperations<String,Object> var = redisTemplate.opsForValue();
        String Userid = "8c1f24dfa0a846d290b11cd74598aba1";
        //设置缓存键
        String redisKey = String.format("com:mo:star:recommend:%s",Userid);
        Page<User> userPage = (Page<User>) var.get(redisKey);
        if(userPage !=null)
            return userPage;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNotNull("tags");
        //缓存为空则读数据库
        userPage=this.page(new Page<>(1,20),queryWrapper);
        log.info("-------------首页的缓存------------");
        try{
            //写缓存进redis
            var.set(redisKey,userPage,3, TimeUnit.DAYS);
        }catch (Exception e){
            log.error("redis set key error",e);
        }
        return userPage;
    }
    public List<User> MatchRedis(User loginUser){
        if(loginUser==null || loginUser.getId() ==null)
            return null;
        ValueOperations<String,Object> var = redisTemplate.opsForValue();
        String Userid = loginUser.getId();
        String redisKey = String.format("com:mo:star:match:%s",Userid);
        List<User> userList = (List<User>) var.get(redisKey);
        if(userList !=null)
            return userList;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
      //  queryWrapper.isNotNull("tags");
        // 使用JSON函数来检查tags字段是否包含至少一个元素
// 假设tags字段存储的是JSON数组
        queryWrapper.apply("json_length(`tags`) > 0");
        userList = this.list(queryWrapper);
        log.info("-------------匹配的缓存------------");
        try{
            //写缓存进redis
            var.set(redisKey,userList,3, TimeUnit.DAYS);
        }catch (Exception e){
            log.error("redis set key error",e);
        }
        return userList;
    }
}




